package com.fmy.security.starter;

import com.fmy.security.cache.CacheOnline;
import com.fmy.security.cache.CacheOnlineImpl;
import com.fmy.security.cache.config.CaffeineConfiguration;
import com.fmy.security.config.TokenProperties;
import com.fmy.security.handel.AuthenticationFailureHandlerImpl;
import com.fmy.security.handel.AuthenticationSuccessHandlerImpl;
import com.fmy.security.service.LoginHandler;
import com.fmy.security.service.TokenExceptionHander;
import com.fmy.security.service.TokenGenerate;
import com.fmy.security.service.defult.LoginHandlerDefult;
import com.fmy.security.service.defult.TokenExceptionHanderDefult;
import com.fmy.security.service.defult.TokenGenerateDefult;
import com.github.benmanes.caffeine.cache.Ticker;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.util.StringUtils;

import java.util.Map;

/**
 * @author Mr.fmy
 * @version 1.0.0
 * @ClassName AuthConfigution
 * @Description TODO
 * @createTime 2019/9/6 15:17
 */
@Configuration
@Slf4j
@EnableCaching
@EnableConfigurationProperties({TokenProperties.class})
public class AuthConfiguation {

    @Bean
    public Ticker ticker() {
        return Ticker.systemTicker();
    }

    @Bean
    @ConditionalOnMissingBean
    public TokenGenerate tokenGenerate() {
        return new TokenGenerateDefult();
    }

    @Bean
    @ConditionalOnMissingBean
    public LoginHandler loginHandler() {
        return new LoginHandlerDefult();
    }

    @Bean
    @ConditionalOnMissingBean
    public TokenExceptionHander tokenExceptionHander() {
        return new TokenExceptionHanderDefult();
    }

    @Bean("securityCacheManager")
    @ConditionalOnProperty(name = "spring.cache.token.enable", havingValue = "true")
    public CacheManager cacheManager(TokenProperties properties, Ticker ticker) {
        return new CaffeineConfiguration(properties).cacheManager(ticker);
    }

    @Bean
    @Primary
    @ConditionalOnProperty(name = "spring.cache.token.appoint", havingValue = "false")
    public CacheOnline cacheOnline(CacheManager cacheManager) {
        return new CacheOnlineImpl(cacheManager);
    }

    @Bean
    @Primary
    @ConditionalOnProperty(name = "spring.cache.token.appoint", havingValue = "true")
    public CacheOnline cacheOnlineEnable(ApplicationContext context, TokenProperties properties) {
        Map<String, CacheManager> cacheManagers = context.getBeansOfType(CacheManager.class);
        if (cacheManagers.size() == 0) throw new IllegalArgumentException("请配置缓存");
        if (StringUtils.isEmpty(properties.getCacheManagerName())) {
            return new CacheOnlineImpl(context.getBean(CacheManager.class));
        }
        if (cacheManagers.containsKey(properties.getCacheManagerName())) {
            return new CacheOnlineImpl(cacheManagers.get(properties.getCacheManagerName()));
        }
        throw new IllegalArgumentException("未找到：" + properties.getCacheManagerName() + " 缓存 bean");
    }

    @Bean
    @Primary
    public AuthenticationSuccessHandler authenticationSuccessHandler(CacheOnline cacheOnline, TokenGenerate tokenService, LoginHandler loginHandler, TokenProperties properties) {
        return new AuthenticationSuccessHandlerImpl(cacheOnline, tokenService, loginHandler, properties);
    }

    @Bean
    @Primary
    public AuthenticationFailureHandler authenticationFailureHandler(LoginHandler loginHandler) {
        return new AuthenticationFailureHandlerImpl(loginHandler);
    }
}
